<html>
<head>
<title>YATE - External module</title>
</head>
<body>
The work on this document is still in progress.
Please do not use it as reference, the specifications are likely to change.

<h1>External module command flow</h1>

<h2>File handles used</h2>
The external user application or script comunicates with the module trough
several file descriptors:<br />
0 (stdin)    - Carries commands and notifications from engine to application<br />
1 (stdout)   - Carries commands and answers from application to the engine<br />
2 (stderr)   - Has the usual meaning of reporting errors and is directed to the	engine's stderr or logfile<br />
3 (optional) - Transports audio data from the engine to the application<br />
4 (optional) - Transports audio data from the application to the engine<br />

File descriptors 3 and 4 are open only for audio capable applications.<br />

<h2>Socket operation</h2>
Yate can start one or more socket listeners and wait for external programs to
connect to them. Depending on the platform, TCP and UNIX sockets may be available.<br />
Once connected, an external program uses this single socket to send commands and
receive answers from the engine.<br />
For reporting errors it is recommended to use the <b>%%&gt;output</b> keyword.<br />
Each listener can have a single role or the connecting program will have to
use the <b>%%&gt;connect</b> command first to esablish a role.<br />

<h2>Format of commands and notifications</h2>

<p>
Words enclosed in &lt;angle brackets&gt; must be replaced with the proper value.<br />

Elements in [square brackets] are optional. An ellipsis ... denotes optional
repetition of the last element.<br />

Every command is sent on its own newline (\n, ^J, decimal 10) delimited line.<br />

Any value that contains special characters (ASCII code lower than 32) MUST have
them converted to %&lt;upcode&gt; where &lt;upcode&gt; is the character with a
numeric value equal with 64 + original ASCII code. The % character itself MUST
be converted to a special %% representation. Characters with codes higher than 32
(except %) SHOULD not be escaped but may be so. A %-escaped code may be received
instead of an unescaped character anywhere except in the initial keyword or the
delimiting colon (:) characters. Anywhere in the line except the initial keyword
a % character not followed by a character with a numeric value higher than 64
(40H, 0x40, '@') or another % is an error.<br />
</p>

<p><b>Special Keyword: Error in</b><br />
Error in:&lt;original&gt;<br />
<b>Direction: Engine to application</b><br />
The engine sends this notification as answer to a syntactically incorrect line
it received from the application.<br />
&lt;original&gt; - the original line exactly as received (not escaped or something)<br />
The external module SHOULD NOT send anything back to Yate in response to such a
notification as it can result in an infinite loop.<br />
</p>

<p><b>Keyword: %%&gt;message</b><br />
%%&gt;message:&lt;id&gt;:&lt;time&gt;:&lt;name&gt;:&lt;retvalue&gt;[:&lt;key&gt;=&lt;value&gt;...]<br />
<b>Direction: Engine to application</b><br />
This line is sent by the engine to the application) to ask it to process a message.
The Yate thread that dispatches the message will block until an answer is
received (see below).<br />
&lt;id&gt; - obscure unique message ID string generated by Yate<br />
&lt;time&gt; - time (in seconds) the message was initially created<br />
&lt;name&gt; - name of the message<br />
&lt;retvalue&gt; - default textual return value of the message<br />
&lt;key&gt;=&lt;value&gt; - enumeration of the key-value pairs of the message<br />
</p>

<p><b>Keyword: %%&lt;message</b><br />
%%&lt;message:&lt;id&gt;:&lt;processed&gt;:[&lt;name&gt;]:&lt;retvalue&gt;[:&lt;key&gt;=&lt;value&gt;...]<br />
<b>Direction: Application to engine</b><br />
One such answer is required for every received message (%%&gt;message). When
the engine gets a line in this format it modifies the provided values back into
the message and let it continue or stop dispatching.<br />
&lt;id&gt; - same message ID string received trough %%&gt;message<br />
&lt;processed&gt; - boolean (&quot;true&quot; or &quot;false&quot;) indication
if the message has been processed or it should be passed to the next handler<br />
&lt;name&gt; - new name of the message, if empty keep unchanged<br />
&lt;retvalue&gt; - new textual return value of the message<br />
&lt;key&gt;=&lt;value&gt; - new key-value pairs to set in the message; to delete
the key-value pair provide just a key name with no equal sign or value<br />
</p>

<p><b>Keyword: %%&gt;message</b><br />
%%&gt;message:&lt;id&gt;:&lt;time&gt;:&lt;name&gt;:&lt;retvalue&gt;[:&lt;key&gt;=&lt;value&gt;...]<br />
<b>Direction: Application to engine</b><br />
This line is sent by the application to the engine to ask it to process a message.
The answer to such a message is delivered asynchronously (see below).<br />
&lt;id&gt; - obscure unique message ID string generated by the application<br />
&lt;time&gt; - time (in seconds) the message was initially created<br />
&lt;name&gt; - name of the message<br />
&lt;retvalue&gt; - default textual return value of the message<br />
&lt;key&gt;=&lt;value&gt; - enumeration of the key-value pairs of the message<br />
</p>

<p><b>Keyword: %%&lt;message</b><br />
%%&lt;message:&lt;id&gt;:&lt;processed&gt;:[&lt;name&gt;]:&lt;retvalue&gt;[:&lt;key&gt;=&lt;value&gt;...]<br />
<b>Direction: Engine to application</b><br />
One such answer is required for every message (%%&gt;message) the application
sent to the engine. It contains the message's return values and parameters.<br />
&lt;id&gt; - same message ID string received trough %%&gt;message<br />
&lt;processed&gt; - boolean (&quot;true&quot; or &quot;false&quot;) indication
if the message has been declared processed by one of the handlers<br />
&lt;name&gt; - name of the message, possibly changed<br />
&lt;retvalue&gt; - textual return value of the message<br />
&lt;key&gt;=&lt;value&gt; - key-value pairs of parameters to the message.<br />
</p>

<p><b>Keyword: %%&gt;install</b><br />
%%&gt;install:[&lt;priority&gt;]:&lt;name&gt;[:&lt;filter-name&gt;[:&lt;filter-value&gt;]]<br />
<b>Direction: Application to engine</b><br />
Always from the application to the engine, requests the installing of a message
handler for the application that requested it<br />
The answer to the install request is delivered asynchronously (see below).<br />
&lt;priority&gt; - priority in chain, use default (100) if missing<br />
&lt;name&gt; - name of the messages for that a handler should be installed<br />
&lt;filter-name&gt; - name of a variable the handler will filter<br />
&lt;filter-value&gt; - matching value for the filtered variable<br />
</p>

<p><b>Keyword: %%&lt;install</b><br />
%%&lt;install:&lt;priority&gt;:&lt;name&gt;:&lt;success&gt;<br />
<b>Direction: Engine to application</b><br />
Confirmation from engine to the application that the handler has been installed
properly or not.<br />
&lt;priority&gt; - priority of the installed handler<br />
&lt;name&gt; - name of the messages asked to handle<br />
&lt;success&gt; - boolean (&quot;true&quot; or &quot;false&quot;) success of operation<br />
</p>

<p><b>Keyword: %%&gt;uninstall</b><br />
%%&gt;uninstall:&lt;name&gt;<br />
<b>Direction: Application to engine</b><br />
Always from the application to the engine, requests uninstalling a previously
installed message handler<br />
The answer to the uninstall request is delivered asynchronously (see below).<br />
&lt;name&gt; - name of the message handler thst should be uninstalled<br />
</p>

<p><b>Keyword: %%&lt;uninstall</b><br />
%%&lt;uninstall:&lt;priority&gt;:&lt;name&gt;:&lt;success&gt;<br />
<b>Direction: Engine to application</b><br />
Confirmation from engine to the application that the handler has been uninstalled
properly or not.<br />
&lt;priority&gt; - priority of the previously installed handler<br />
&lt;name&gt; - name of the message handler asked to uninstall<br />
&lt;success&gt; - boolean (&quot;true&quot; or &quot;false&quot;) success of operation<br />
</p>

<p><b>Keyword: %%&gt;watch</b><br />
%%&gt;watch:&lt;name&gt;<br />
<b>Direction: Application to engine</b><br />
Always from the application to the engine, requests the installing of a message
watcher (post-dispatching notifier) for the application that requested it<br />
The answer to the watch request is delivered asynchronously (see below).<br />
&lt;name&gt; - name of the messages for that a watcher should be installed<br />
</p>

<p><b>Keyword: %%&lt;watch</b><br />
%%&lt;watch:&lt;name&gt;:&lt;success&gt;<br />
<b>Direction: Engine to application</b><br />
Confirmation from engine to the application that the watcher has been installed
properly or not.<br />
&lt;name&gt; - name of the messages asked to watch<br />
&lt;success&gt; - boolean (&quot;true&quot; or &quot;false&quot;) success of operation<br />
</p>

<p><b>Keyword: %%&gt;unwatch</b><br />
%%&gt;unwatch:&lt;name&gt;<br />
<b>Direction: Application to engine</b><br />
Always from the application to the engine, requests uninstalling a previously
installed message watcher<br />
The answer to the unwatch request is delivered asynchronously (see below).<br />
&lt;name&gt; - name of the message watcher thst should be uninstalled<br />
</p>

<p><b>Keyword: %%&lt;unwatch</b><br />
%%&lt;unwatch:&lt;name&gt;:&lt;success&gt;<br />
<b>Direction: Engine to application</b><br />
Confirmation from engine to the application that the watcher has been uninstalled
properly or not.<br />
&lt;name&gt; - name of the message watcher asked to uninstall<br />
&lt;success&gt; - boolean (&quot;true&quot; or &quot;false&quot;) success of operation<br />
</p>

<p><b>Keyword: %%&gt;setlocal</b><br />
%%&gt;setlocal:&lt;name&gt;:&lt;value&gt;<br />
<b>Direction: Application to engine</b><br />
Always from the application to the engine, requests the change of a local
parameter<br />
The answer to the change request is delivered asynchronously (see below).<br />
&lt;name&gt; - name of the parameter to modify, must not be empty<br />
&lt;value&gt; - new value to set in the local module instance, empty to just query<br />
For read-only parameters you must provide an empty value.<br />
<b>Currently supported parameters:</b><br />
id (string) - Identifier of the associated channel, if any<br />
disconnected (bool) - Enable or disable sending &quot;chan.disconnected&quot; messages<br />
trackparam (string) - Set the message handler tracking name, cannot be made empty<br />
reason (string) - Set the disconnect reason that gets received by the peer channel<br />
timeout (int) - Timeout in milliseconds for answering to messages<br />
timebomb (bool) - Terminate this module instance if a timeout occured<br />
setdata (bool) - Attach channel pointer as user data to generated messages<br />
reenter (bool) - If this module is allowed to handle messages generated by itself<br />
selfwatch (bool) - If this module is allowed to watch messages generated by itself<br />
restart (bool) - Restart this global module if it terminates unexpectedly. Must be turned off to allow normal termination<br />
<b>Engine read-only run parameters:</b><br />
engine.version (string,readonly) - Version of the engine, like &quot;2.0.1&quot;<br />
engine.release (string,readonly) - Release type and number, like &quot;beta2&quot;<br />
engine.nodename (string,readonly) - Server's node name as known by the engine<br />
engine.runid (int,readonly) - Engine's run identifier<br />
engine.configname (string,readonly) - Name of the master configuration<br />
engine.sharedpath (string,readonly) - Path to the shared directory<br />
engine.configpath (string,readonly) - Path to the program config files directory<br />
engine.cfgsuffix (string,readonly) - Suffix of the config files names, normally &quot;.conf&quot;<br />
engine.modulepath (string,readonly) - Path to the main modules directory<br />
engine.modsuffix (string,readonly) - Suffix of the loadable modules, normally &quot;.yate&quot;<br />
engine.logfile (string,readonly) - Name of the log file if in use, empty if not logging<br />
engine.clientmode (bool,readonly) - Check if running as a client<br />
engine.supervised (bool,readonly) - Check if running under supervisor <br />
engine.maxworkers (int,readonly) - Maximum number of message worker threads<br />
<b>Engine configuration file parameters:</b><br />
config.&lt;section&gt;.&lt;key&gt; (readonly) - Content of key= in [section] of main config file (yate.conf, yate-qt4.conf)<br />
</p>

<p><b>Keyword: %%&lt;setlocal</b><br />
%%&lt;setlocal:&lt;name&gt;:&lt;value&gt;:&lt;success&gt;<br />
<b>Direction: Engine to application</b><br />
Confirmation from engine to the application that the local parameter has been
changed successfully or not.<br />
&lt;name&gt; - name of the modified parameter<br />
&lt;value&gt; - new value of the local parameter<br />
&lt;success&gt; - boolean (&quot;true&quot; or &quot;false&quot;) success of operation<br />
</p>

<p><b>Keyword: %%&gt;output</b><br />
%%&gt;output:arbitrary unescaped string<br />
<b>Direction: Application to engine</b><br />
The &quot;output&quot; keyword is used to relay arbitrary output messages to
engine's logging output.<br />
This is the proper way of logging messages for programs that connect to the
socket interface as they may not have the standard error redirected.<br />
</p>

<p><b>Keyword: %%&gt;connect</b><br />
%%&gt;connect:&lt;role&gt;[:&lt;id&gt;][:&lt;type&gt;]<br />
<b>Direction: Application to engine</b><br />
The &quot;connect&quot; keyword is used only by external modules that attach to
the socket interface. As the conection is initiated from the external module the
engine must be informed on the role of the connection.<br />
This must be the first request sent over a newly established socket connection.
The role and direction of the connection is established and then this keyword
cannot be used again on the same connection.<br />
There is no answer to this request - if it fails the engine will slam the
connection shut.<br />
Connections with a role of play, record or playrec are data connections and must
be attached to a valid control channel. Any existing data endpoint with the same
type and direction is closed.<br />
&lt;role&gt; - role of this connection: global, channel, play, record, playrec<br />
&lt;id&gt; - channel id to connect this socket to<br />
&lt;type&gt; - type of data channel, assuming audio if missing<br />
</p>

<h2>Example</h2>
<p>
In the example below the lines sent from application to engine are prefixed with
A: while lines sent from engine to application are prefixed with E:<br />
Comments are indented<br />
</p>

<pre>

    Application installs a handler for a "test" handler with priority 50
A: %%&gt;install:50:test

    Engine installs the handler and acknowledges it
E: %%&lt;install:50:test:true

    Application installs a handler for the "engine.timer" handler with default priority
A: %%&gt;install::engine.timer

    Engine installs the handler and acknowledges it
E: %%&lt;install:100:engine.timer:true

    Application emits a private "app.job" message; notice how the '%' and ':' characters were escaped
A: %%&gt;message:myapp55251:1095112794:app.job::job=cleanup:done=75%%:path=/bin%Z/usr/bin

    Engine just dispatched an "engine.timer" message
E: %%&gt;message:234479208:1095112795:engine.timer::time=1095112795

    Engine gets back the answer to the "app.job" message with a "Restart required" returned text value
E: %%&lt;message:myapp55251:true:app.job:Restart required:path=/bin%Z/usr/bin%Z/usr/local/bin

    Application ignores the timer message
A: %%&lt;message:234479208:false:engine.timer::time=1095112795

    Application uninstalls the "test" handler
A: %%&gt;uninstall:test

    Engine removes the handler and acknowledges it
E: %%&lt;uninstall:50:test:true

    Engine just dispatched another "engine.timer" message
E: %%&gt;message:234479288:1095112796:engine.timer::time=1095112796

    Application modifies the timer message but lets it flow further
A: %%&lt;message:234479288:false:engine.timer::time=1095112796:extra=yes

    Engine just dispatched another "engine.timer" message
E: %%&gt;message:234479244:1095112797:engine.timer::time=1095112797

    Application suddenly exits without acknowledging previous message.
    The engine releases the message 234479244 (as if "false" was returned) and
    uninstalls the remaining "engine.timer" handler
</pre>

</body>
</html>
